package com.net.tool;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Vector;

import com.tools.SycSqlite;

import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;

public abstract class BasicDownload {

	public static final int DOWNLOAD_STATTE_FAILE = 7; // 下载失败
	public static final int DOWNLOAD_STATTE_COMPLATAE = 5; // 下载结束
	public static final int DOWNLOAD_STATTE_CANCAL = 6; // 取消下载
	public static final int DOWNLOAD_STATTE_DOWNLOADING = 10;// 正在下载；
	public static final int DOWNLOAD_STATE_PREPARE = 9;// 准备状态；
	public static final int DOWNLOAD_STATE_PENDING = 8; // 挂起状态；
	public static final int DOWNLOAD_STATE_REMOVE = 4;// 打断

	public static final int STATE_NETWORK_ERROR = -1;
	public static final int STATE_SDCARD_LEFT = -2;
	public static final int STATE_SDCARD_DENIED = -3;

	public static class DownLoadInfo {
		public String mTitle;
		public String mTaskId;
		public String mIcon;
		public int mState;
		public int mTaskSize;
		public int mStateExtr;
		public int mFileSize;
		public String mFilePath;

		@Override
		public String toString() {
			// TODO Auto-generated method stub
			return mTitle + "  " + mTaskId + " " + mIcon + " " + mState + " "
					+ mFileSize + " " + mTaskSize + " " + mStateExtr;
		}

	}

	public static final String APK_ROOTP_PATH = Environment.getExternalStorageDirectory().getPath()+".dailyyogaCN2/APKS/";

	String mClintPath; // 客户端文件路径

	static protected Context mContext;

	public static interface DownloadListner {

		public void download(String taskId, int progress, int length);

		public void stateChange(String taskId, int state, int... is);

	}

	static DownloadTable mDownloadTable; // 下载的任务表；

	static Vector<DownloadListner> mDownloadListnerVector; // 下载监听器

	static {
		mDownloadListnerVector = new Vector<BasicDownload.DownloadListner>();
	}

	int mPriority; // 任务优先级

	int mServerVc; // 服务端版本号

	protected String mDownloadTaskId; // 下载的ID；

	/**
	 * 
	 * @author 下载数据库
	 * 
	 */

	public static final class DownloadTable extends SQLiteOpenHelper {

		public static String TB_NAME = "DownloadTable"; // 下载的数据库的表
		public static String TASKID = "pkg"; // 数据包的ID
		public static String TASKSIZE = "taskSize"; // 数据包的服务器端的大小
		public static String TASKSTATE = "taskState"; // 数据包的状态
		public static String TASKURL = "url"; // 数据包的地址
		public static String SERVER_VC = "vc"; // 服务器端数据包的版本号；
		public static String FROM = "source"; // 数据源
		public static String PRIORITY = "priority";// 优先级
		public static String CLASS = "class";//
		public static String ID = "_id";//
		public static String TASKICON = "taskicon";// 任务图标
		public static String STATEEXTR = "stateextr";// 状态附加字段
		public static String TASKTITLE = "tasktitle";// 任务标题

		public DownloadTable(Context context, String name,
				CursorFactory factory, int version) {
			super(context, name, factory, version);
		}

		public void onCreate(SQLiteDatabase db) {
			db.execSQL("CREATE TABLE IF NOT EXISTS " + DownloadTable.TB_NAME
					+ " (" + DownloadTable.TASKID + " text PRIMARY KEY,"
					+ DownloadTable.ID + " INTEGER," + DownloadTable.SERVER_VC
					+ " INTEGER NOT NULL DEFAULT -1," + DownloadTable.TASKSIZE
					+ " INTEGER NOT NULL DEFAULT -1," + DownloadTable.TASKSTATE
					+ " INTEGER NOT NULL DEFAULT " + DOWNLOAD_STATE_REMOVE
					+ "," + DownloadTable.PRIORITY
					+ " INTEGER NOT NULL DEFAULT -1," + DownloadTable.CLASS
					+ " text," + DownloadTable.TASKURL + " text,"
					+ DownloadTable.TASKTITLE + " text,"
					+ DownloadTable.TASKICON + " text,"
					+ DownloadTable.STATEEXTR + " INTEGER,"
					+ DownloadTable.FROM + " text)");
		}

		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			db.execSQL("DROP TABLE " + TB_NAME);
			onCreate(db);

		}
	}

	HttpURLConnection mConnection;

	/**
	 * 获取服务器端文件大小
	 * 
	 * @param urlPath
	 * @return
	 * @throws IOException
	 */

	long getDownloadTaskSize(String urlPath) throws IOException {

		Log.d("download", "服务器端的大小" + "urlPath====" + urlPath);

		URL url = new URL(urlPath);
		mConnection = (HttpURLConnection) url.openConnection();
		// mConnection.setConnectTimeout(1000);
		// mConnection.setReadTimeout(1000);
		mConnection.setRequestMethod("GET");
		long fileSize = mConnection.getContentLength();
		mConnection.disconnect();

		return fileSize;

	}

	/**
	 * 获取客户端缓存文件
	 * 
	 * @param fileName
	 * @return
	 * @throws IOException
	 */
	protected RandomAccessFile getSavaFile(String fileName) throws IOException {

		File file = new File(APK_ROOTP_PATH + fileName);

		if (!file.exists()) {
			file.createNewFile();
		}

		mClintPath = APK_ROOTP_PATH + fileName;

		RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");

		return accessFile;

	}

	/**
	 * 获取客户端缓存文件大小
	 * 
	 * @param path
	 * @return
	 * @throws IOException
	 */
	long getClintFileSize(String path) throws IOException {

		Log.d("download", path);

		File file = new File(APK_ROOTP_PATH);

		if (!file.exists()) {
			file.mkdirs();
		}

		file = new File(file, path);

		if (!file.exists()) {
			file.createNewFile();
		}

		RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");

		long lenght = accessFile.length();

		accessFile.close();

		return lenght;

	}

	/**
	 * 删除客户端文件
	 * 
	 * @param path
	 */
	void deletClintFile(String path) {

		File file = new File(APK_ROOTP_PATH + path);

		Log.d("download", "delete" + file.getName() + " " + file.delete());
	}

	public static SycSqlite getSqlite(Context context) {

		if (mDownloadTable == null) {
			mDownloadTable = new DownloadTable(context, "download.db", null, 2);
		}
		SQLiteDatabase liteDatabase = mDownloadTable.getWritableDatabase();

		return new SycSqlite(liteDatabase);

	}

	/**
	 * 清楚上次缓存文件
	 * 
	 * @param taskId
	 *            //现在任务ID；
	 * @param server_vc
	 *            // 数据服务器端版本号；
	 */
	void clearJunkfiles(String taskId, int server_vc) {

		File file = new File(APK_ROOTP_PATH);

		File[] files = file.listFiles();
		if (files == null) {
			return;
		}

		for (File item : files) {

			if (item != null) {

				if (item.getName().contains(taskId)
						&& !item.getName().equals(taskId + server_vc + ".apk")) {
					item.delete();
				}
			}

		}

	}

	private void updateProgress(String taskId, int progress, int length) {

		synchronized (mDownloadListnerVector) {

			for (DownloadListner iterable_element : mDownloadListnerVector) {
				iterable_element.download(taskId, progress, length);
			}
		}

	}

	int mFailedEx = 0;// 下载失败的状态

	int mDownloadState = 0; // 下载的状态

	String mUrl;

	/**
	 * 执行下载
	 * 
	 * @param downloadId
	 *            下载任务的ID
	 * @param url
	 *            下载的URL
	 * @param clintPath
	 *            客户端文件存放路径
	 * @return 是否下载成功
	 */
	@SuppressWarnings("resource")
	boolean download(String downloadId, String url, String clintPath) {

		synchronized (downloadId) {

			mUrl = url;

			Log.d("download", "url=" + mUrl);

			Log.d("download", "执行下载download=" + downloadId + " = " + url
					+ " = " + clintPath);

			boolean flag = true;

			RandomAccessFile randomAccessFile = null;

			InputStream is = null;

			try {

				if (mDownloadState != DOWNLOAD_STATTE_DOWNLOADING) {
					Log.d("download", "状态不对 mDownloadState");
					throw new Exception(
							"mDownloadState!=DOWNLOAD_STATTE_DOWNLOADING");
				}

				long clintFileLength = getClintFileSize(clintPath);

				Log.d("download", " clintFileLength = " + clintFileLength);

				if (mDownloadState != DOWNLOAD_STATTE_DOWNLOADING) {
					Log.d("download", "状态不对 mDownloadState");
					throw new Exception(
							"mDownloadState!=DOWNLOAD_STATTE_DOWNLOADING");
				}

				URL urlstr = new URL(url);
				mConnection = (HttpURLConnection) urlstr.openConnection();
				mConnection.setRequestMethod("GET");
				mConnection.setRequestProperty("Range", "bytes="
						+ (clintFileLength) + "-");

				long serverLength = mConnection.getContentLength();

				Log.d("serverLength", "serverLength=" + serverLength
						+ mConnection.getResponseMessage() + " code ="
						+ mConnection.getResponseCode());

				if (serverLength < 0) {
					throw new Exception("serverLength<0");
				}

				if (mConnection.getResponseCode() == 416) {

					throw new Exception("416");

				}

				is = mConnection.getInputStream();

				updataTaskState(DOWNLOAD_STATTE_DOWNLOADING);

				serverLength += clintFileLength;
				ContentValues contentValues = new ContentValues();
				contentValues.put(DownloadTable.TASKSIZE, serverLength);
				getSqlite(mContext).update(DownloadTable.TB_NAME,
						contentValues, DownloadTable.TASKID + "=?",
						new String[] { mDownloadTaskId });

				randomAccessFile = getSavaFile(clintPath);

				randomAccessFile.seek(clintFileLength);

				if (mDownloadState != DOWNLOAD_STATTE_DOWNLOADING) {
					Log.d("download", "状态不对 mDownloadState");
					throw new Exception(
							"mDownloadState!=DOWNLOAD_STATTE_DOWNLOADING");
				} else {
					Log.d("download", "开始读取数据");
				}

				byte[] buffer = new byte[1024];
				int length = -1;

				while ((length = is.read(buffer)) != -1) {

					int progress = (int) (clintFileLength += length);
					randomAccessFile.write(buffer, 0, length);

					if (mDownloadState != DOWNLOAD_STATTE_DOWNLOADING) {
						Log.d("download", "状态不对 mDownloadState");
						throw new Exception(
								"mDownloadState!=DOWNLOAD_STATTE_DOWNLOADING");
					}

					updateProgress(mDownloadTaskId, progress,
							(int) serverLength);

					Log.d("download", this + mDownloadTaskId + "  执行下载  = "
							+ progress + " sl=" + serverLength);

				}

			} catch (Exception e) {

				e.printStackTrace();
				flag = false;
				if (e.getMessage() != null
						&& (e.getMessage().contains("sdcard"))) {

					if (e.getMessage().contains("Permission denied")) {
						mFailedEx = STATE_SDCARD_DENIED;
					} else if (e.getMessage().contains(
							"No space left on device")) {
						mFailedEx = STATE_SDCARD_LEFT;
					}
				} else if (e.getMessage() != null
						&& e.getMessage().equals("416")) {
					flag = true;

				} else {
					mFailedEx = STATE_NETWORK_ERROR;
				}

			} finally {

				try {

					if (is != null) {
						is.close();
					}
					if (randomAccessFile != null) {
						randomAccessFile.close();
					}
					if (mConnection != null) {
						mConnection.disconnect();
					}

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return flag;
		}
	}

	void updataTaskState(int state, int... is) {

		synchronized (BasicDownload.class) {
			mDownloadState = state;
			ContentValues contentValues = new ContentValues();
			contentValues.put(DownloadTable.TASKSTATE, state);

			if (state == DOWNLOAD_STATTE_FAILE) {
				contentValues.put(DownloadTable.STATEEXTR, is[0]);
			}

			getSqlite(mContext).update(DownloadTable.TB_NAME, contentValues,
					DownloadTable.TASKID + "=?",
					new String[] { mDownloadTaskId });
		}

		synchronized (mDownloadListnerVector) {

			for (DownloadListner downloadListner : mDownloadListnerVector) {
				downloadListner.stateChange(mDownloadTaskId, state, is);
			}
		}

		Log.d("updataTaskState", mDownloadTaskId + " mDownloadState ="
				+ mDownloadState);

	}

	protected static void fixNetworkERROR(Context context) {
		synchronized (BasicDownload.class) {
			ContentValues contentValues = new ContentValues();
			contentValues.put(DownloadTable.TASKSTATE, DOWNLOAD_STATE_PREPARE);
			getSqlite(context).update(
					DownloadTable.TB_NAME,
					contentValues,
					DownloadTable.TASKSTATE + "=? AND "
							+ DownloadTable.STATEEXTR + "=?",
					new String[] { DOWNLOAD_STATTE_FAILE + "",
							STATE_NETWORK_ERROR + "", });
		}
		synchronized (mDownloadListnerVector) {
			for (DownloadListner downloadListner : mDownloadListnerVector) {
				downloadListner.stateChange(null, DOWNLOAD_STATE_PREPARE);
			}
		}
	}

	protected static void fixSdcardError(Context context) {

		synchronized (BasicDownload.class) {

			ContentValues contentValues = new ContentValues();
			contentValues.put(DownloadTable.TASKSTATE, DOWNLOAD_STATE_PREPARE);
			getSqlite(context).update(
					DownloadTable.TB_NAME,
					contentValues,
					DownloadTable.TASKSTATE + "=? AND "
							+ DownloadTable.STATEEXTR + "!=?",
					new String[] { DOWNLOAD_STATTE_FAILE + "",
							STATE_NETWORK_ERROR + "", });
		}

	}

	protected static void updataTaskState(int state, String taskId,
			Context context) {

		ContentValues contentValues = new ContentValues();
		contentValues.put(DownloadTable.TASKSTATE, state);
		getSqlite(context).update(DownloadTable.TB_NAME, contentValues,
				DownloadTable.TASKID + "=?", new String[] { taskId });

		if (state == DOWNLOAD_STATE_REMOVE) {

			try {
				new File(getTaskDetail(taskId, context).mFilePath).delete();
			} catch (Exception e) {
				// TODO: handle exception
			}

		}

		synchronized (mDownloadListnerVector) {
			for (DownloadListner downloadListner : mDownloadListnerVector) {
				downloadListner.stateChange(taskId, state);
			}
		}

	}

	/**
	 * 执行下载
	 */
	public abstract void downloading();

	/**
	 * 取消下载任务
	 */
	public void cancal() {

		updataTaskState(DOWNLOAD_STATTE_CANCAL);

		BgkTaskMange.getInstance().executeCommend(new AsyncCommend() {

			public void asyncCommend() {
				if (mConnection != null) {
					mConnection.disconnect();
				}
			}
		});
	}

	public void remove() {
		updataTaskState(DOWNLOAD_STATE_REMOVE);
		BgkTaskMange.getInstance().executeCommend(new AsyncCommend() {
			public void asyncCommend() {
				if (mConnection != null) {
					mConnection.disconnect();
				}
			}
		});

	}

	/**
	 * 挂起正在下载的任务
	 */
	public void pending() {

		updataTaskState(DOWNLOAD_STATE_PENDING);

		BgkTaskMange.getInstance().executeCommend(new AsyncCommend() {
			public void asyncCommend() {
				if (mConnection != null) {
					mConnection.disconnect();
				}
			}
		});

	}

	/**
	 * 
	 * 设置下载监听
	 * 
	 * @param downloadListner
	 */
	public static void registerDownloadListner(DownloadListner downloadListner) {

		synchronized (mDownloadListnerVector) {
			if (mDownloadListnerVector.indexOf(downloadListner) == -1) {
				mDownloadListnerVector.addElement(downloadListner);
			}
		}

	}

	/**
	 * 
	 * 设置下载监听
	 * 
	 * @param downloadListner
	 */
	public static void unRegisterDownloadListner(DownloadListner downloadListner) {
		synchronized (mDownloadListnerVector) {
			mDownloadListnerVector.removeElement(downloadListner);
		}
	}

	/**
	 * 打开APK 文件
	 * 
	 * @param file
	 */
	void openApkFile(File file) {
		Intent intent = new Intent();
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		intent.setAction(android.content.Intent.ACTION_VIEW);
		intent.setDataAndType(Uri.fromFile(file),
				"application/vnd.android.package-archive");
		mContext.startActivity(intent);

	}

	public BasicDownload(Context context) {
		mContext = context;

	}

	public static DownLoadInfo getTaskDetail(String taskId, Context context) {

		synchronized (BasicDownload.class) {

			Cursor cursor = getSqlite(mContext).query(
					DownloadTable.TB_NAME,
					new String[] { DownloadTable.SERVER_VC,
							DownloadTable.TASKICON, DownloadTable.TASKSTATE,
							DownloadTable.TASKTITLE, DownloadTable.TASKSIZE,
							DownloadTable.STATEEXTR, },
					DownloadTable.TASKID + "=?", new String[] { taskId }, null,
					null, null);

			if (cursor.moveToFirst()) {

				DownLoadInfo downLoadInfo = new DownLoadInfo();

				downLoadInfo.mFilePath = APK_ROOTP_PATH + taskId
						+ cursor.getInt(0) + ".apk";
				downLoadInfo.mFileSize = (int) (new File(downLoadInfo.mFilePath)
						.length());
				downLoadInfo.mIcon = cursor.getString(1);
				downLoadInfo.mState = cursor.getInt(2);
				downLoadInfo.mTitle = cursor.getString(3);
				downLoadInfo.mTaskSize = cursor.getInt(4);
				downLoadInfo.mTaskId = taskId;
				downLoadInfo.mStateExtr = cursor.getInt(5);
				cursor.close();
				return downLoadInfo;
			}
			cursor.close();
			return null;
		}

	}

	public boolean checkmPriority() {
		synchronized (BasicDownload.class) {

			Cursor cursor = getSqlite(mContext).query(
					DownloadTable.TB_NAME,
					new String[] { DownloadTable.TASKSTATE },
					DownloadTable.TASKID + "!=? and " + DownloadTable.PRIORITY
							+ ">? and " + DownloadTable.TASKSTATE + " =? ",
					new String[] { mDownloadTaskId, mPriority + "",
							DOWNLOAD_STATE_PREPARE + "" }, null, null, null);

			int count = cursor.getCount();
			cursor.close();
			return count < 1;
		}

	}

	public static int getTaskState(Context context, String taskId) {

		synchronized (BasicDownload.class) {
			int state = -1;
			Cursor cursor = getSqlite(context).query(DownloadTable.TB_NAME,
					new String[] { DownloadTable.TASKSTATE },
					DownloadTable.TASKID + "=?", new String[] { taskId }, null,
					null, null);
			if (cursor.moveToFirst()) {
				state = cursor.getInt(0);
			}
			cursor.close();

			return state;
		}
	}

}
